---------------------------------------------------------------
--
-- segment_cntrl - controls the 7 segment display of the nexys2
-- Made 2012 by Ed Crampton <eddie.crampton@gmail.com>
-- 
--
-- This product is released under the terms of the WTFPL. Read
-- http://sam.zoy.org/wtfpl for more details.
--
---------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
--use ieee.std_logic_arith.all;

entity Seg is
	Generic( n: integer := 18);
    Port ( AN : out  STD_LOGIC_VECTOR (3 downto 0);
			Clock_In : in  STD_LOGIC;
			Data_In : in  STD_LOGIC_VECTOR( 7 downto 0);
			Data_Out : out  STD_LOGIC_VECTOR( 7 downto 0);
			Addr_In : in  STD_LOGIC_VECTOR( 4 downto 0);
			CS_In   : in std_logic;
			RESET_IN : in std_logic;
			CA : out  STD_LOGIC_VECTOR (7 downto 0));
end Seg;

architecture Behavioral of Seg is
signal divide_clk : std_logic := '0';
signal refresh_out : std_logic := '0';
signal r_an : std_logic_vector(3 downto 0) := "1110";
signal value_reg :std_logic_vector(15 downto 0) := x"0000";
signal value_dp_reg :std_logic_vector(3 downto 0) := "0000";
--add array for numbers yo
type TABLE is array(0 to 15) of std_logic_vector(6 downto 0);
constant ascii_table : TABLE := (
 "1000000",  --0
 "1111001", --1
 "0100100", --2
 "0110000", --3
 "0011001", --4
 "0010010", --5
 "0000010", --6
 "1111000", --7
 "0000000", --8
 "0011000", --9
 "0001000", --A
 "0000011", --b
 "1000110", --C
 "0100001", --D
 "0000110", --E
 "0001110" --F
 
);

-- constant ONE : std_logic_vector(7 downto 0):= "11111001";
-- constant TWO : std_logic_vector(7 downto 0):= "10100100";
-- constant THREE : std_logic_vector(7 downto 0):= "10110000";
-- constant FOUR : std_logic_vector(7 downto 0):= "10011001";
-- constant FIVE : std_logic_vector(7 downto 0):= "10110010";
-- constant SIX : std_logic_vector(7 downto 0):= "10000010";
-- constant SEVEN : std_logic_vector(7 downto 0):= "11111000";
-- constant EIGHT : std_logic_vector(7 downto 0):= "10000000";
-- constant NINE : std_logic_vector(7 downto 0):= "10011000";
-- constant ZERO : std_logic_vector(7 downto 0):= "11000000";
-- constant chH	: std_logic_vector(7 downto 0):= "10001011";
-- constant chO : std_logic_vector(7 downto 0):=   "10100011";
-- constant chSPACE : std_logic_vector(7 downto 0):=   "11111111";

--signal segment : STD_LOGIC_VECTOR (7 downto 0) := "11111111";
signal segment1 : STD_LOGIC_VECTOR (6 downto 0) := ascii_table(0);
signal segment2 : STD_LOGIC_VECTOR (6 downto 0) := ascii_table(0);
signal segment3 : STD_LOGIC_VECTOR (6 downto 0) := ascii_table(0);
signal segment4 : STD_LOGIC_VECTOR (6 downto 0) := ascii_table(0);
signal dotpixel : STD_LOGIC_VECTOR (3 downto 0) := "1111";

--type ASCIISTR is array(5 downto 0) of std_logic_vector(7 downto 0);
--signal str: ASCIISTR := (chSPACE,chO,chH,chSPACE,chO,chH);

--constants
constant SEG_MODE_WREGISTER : std_logic_vector(4 downto 0) := "00001"; --01 component select --01 mode register
constant SEG_VALUE_LO_WREGISTER : std_logic_vector(4 downto 0) := "00010"; --01 component select --01 value register
constant SEG_VALUE_HI_WREGISTER : std_logic_vector(4 downto 0) := "00011"; --01 component select --01 value register
constant SEG_VALUE_DP_WREGISTER : std_logic_vector(4 downto 0) := "00100"; --01 component select --01 value register
constant SEG_MODE_RREGISTER : std_logic_vector(4 downto 0) := "10001"; --01 component select --11 read mode register
constant SEG_VALUE_LO_RREGISTER : std_logic_vector(4 downto 0) := "10010"; --01 component select --11 read value register
constant SEG_VALUE_HI_RREGISTER : std_logic_vector(4 downto 0) := "10011"; --01 component select --11 read value register
constant SEG_VALUE_DP_RREGISTER : std_logic_vector(4 downto 0) := "10100"; --01 component select --11 read value register
constant MODE1 : std_logic_vector(7 downto 0) := x"01"; --Static Display
constant MODE2 : std_logic_vector(7 downto 0) := x"02"; --Static Inverse Display
constant MODE3 : std_logic_vector(7 downto 0) := x"03"; --undefined
constant MODE4 : std_logic_vector(7 downto 0) := x"04";

signal mode_reg : std_logic_vector(7 downto 0) := x"00";
signal update_mode_sig : std_logic;

-- type mainState is (
		-- SEG_UPDATE_ST,
		-- SEG_DISPLAY_ST,
		-- SEG_IDISPLAY_ST
		-- );
		
-- signal current_st	:	mainState := SEG_UPDATE_ST;

begin


--LED PROCESS--
Data_Out <=  value_reg(7 downto 0) when ((CS_In = '1') and (Addr_In(4 downto 0) = SEG_VALUE_LO_RREGISTER)) 
											else value_reg(15 downto 8) when ((CS_In = '1') and (Addr_In(4 downto 0) = SEG_VALUE_HI_RREGISTER))
											else mode_reg when ((CS_In = '1') and  (Addr_In(4 downto 0) = SEG_MODE_RREGISTER))
											else ("0000" & value_dp_reg) when ((CS_In = '1') and  (Addr_In(4 downto 0) = SEG_VALUE_DP_RREGISTER))
											else "00000000";
	
process(Clock_In)
	begin
		if(rising_edge(Clock_In)) then
			update_mode_sig <= '0';
			
			--write to register
			if(Addr_In(4 downto 0) = SEG_MODE_WREGISTER and CS_In = '1') then
				mode_reg <= Data_In;
				update_mode_sig <= '1';
			end if;
			
			if(Addr_In(4 downto 0)  = SEG_VALUE_HI_WREGISTER and CS_In = '1') then
				value_reg(7 downto 0) <= Data_In;
				segment3 <= ascii_table(to_integer(unsigned(Data_In(3 downto 0))));
				segment4 <= ascii_table(to_integer(unsigned(Data_In(7 downto 4))));
				--update_mode_sig <= '1';
			end if;
			
			if(Addr_In(4 downto 0)  = SEG_VALUE_LO_WREGISTER and CS_In = '1') then
				value_reg(15 downto 8) <= Data_In;
				segment1 <= ascii_table(to_integer(unsigned(Data_In(3 downto 0))));
				segment2 <= ascii_table(to_integer(unsigned(Data_In(7 downto 4))));
				--update_mode_sig <= '1';
			end if;
			
			if(Addr_In(4 downto 0)  = SEG_VALUE_DP_WREGISTER and CS_In = '1') then
				value_dp_reg <= Data_In(3 downto 0);
				dotpixel <= Data_In(3 downto 0) xor "1111";
				--update_mode_sig <= '1';
			end if;
			--end write to register
			
			if (RESET_In = '1') then
				--current_st <= LED_UPDATE_ST;
				--seg_sig <= x"00";
				value_reg <= x"0000";
				mode_reg <= x"00";
			end if;
			
		end if;
end process;

--CA <= "10000000";

clk_process : process(Clock_In)
begin
	if falling_edge(Clock_In) then
		divide_clk <= not(divide_clk);
	end if;

end process;

divide_process : process(divide_clk)
Variable count : integer range 0 to ((2**N)- 1);
begin
	
	if falling_edge(divide_clk) then
		count := count + 1;
		if(count = 40000) then 
			count := 0;
			refresh_out <= not(refresh_out);
		end if;		
	end if;

end process;

refresh_process : process(refresh_out)

begin
	if falling_edge(refresh_out) then
		AN <= r_an;
		
		case r_an is
		
			when "1110" => --Fourth Segment
				CA(6 downto 0) <= segment4;
				CA(7) <= dotpixel(3);
			when "1101" => --Third Segment
				CA(6 downto 0) <= segment3;
				CA(7) <= dotpixel(2);
			when "1011" =>  --Second Segment
				CA(6 downto 0) <= segment2;
				CA(7) <= dotpixel(1);
			when "0111" => --First Segment
				CA(6 downto 0) <= segment1;
				CA(7) <= dotpixel(0);
			when others =>
				CA(7 downto 0) <= "11111111";
		end case;

		r_an <= r_an(2 downto 0) & r_an(3);
		--CA <= segment;	
		
	end if;

end process;



-- update_process : process(refresh_out)
-- Variable count1 : integer range 0 to 127;
-- begin

	-- if rising_edge(refresh_out) then
			-- count1 := count1 + 1;
		-- if(count1 = 127) then 
			-- count1 := 0;
			-- segment1 <= str(0);
			-- segment2 <= str(1);
			-- segment3 <= str(2);
			-- segment4 <= str(3);

			----segment1 <= ONE;
			----segment2 <= TWO;
			----segment3 <= THREE;
			----segment4 <= FOUR;
			
		-- end if;		
	-- end if;

-- end process;

end Behavioral;